package com.biboheart.adapter.compiler.lexical;

import com.biboheart.adapter.compiler.enums.CharType;
import com.biboheart.adapter.compiler.enums.TokenState;
import com.biboheart.adapter.compiler.enums.TokenType;
import com.biboheart.adapter.compiler.token.Token;
import com.biboheart.adapter.compiler.utils.TokenUtils;
import com.biboheart.adapter.support.utils.ObjectTypeUtils;

/**
 * NULL 分词器
 */
final class TokenizerNull implements Tokenizer {
    private TokenBuffer tokenBuffer;
    private TokenState state;

    @Override
    public TokenState entry(char ch, int offset, String content) {
        state = TokenState.STATE_FAIL;
        if (ch != 'n' && ch != 'N') {
            return state;
        }
        if (offset > content.length() - 4) {
            return state;
        }
        tokenBuffer = new TokenBuffer(offset);
        tokenBuffer.push(ch);
        state = TokenState.STATE_CONTINUE;
        return state;
    }

    @Override
    public TokenState getState() {
        return state;
    }

    @Override
    public TokenState analyse(char ch, int offset, String content) {
        if (TokenState.STATE_END.equals(state)) {
            return TokenState.STATE_END_BACK;
        }
        if (!TokenState.STATE_CONTINUE.equals(state)) {
            return state;
        }
        CharType charType = TokenUtils.getCharType(ch);
        if (!CharType.CHAR_LETTER.equals(charType)) {
            state = TokenState.STATE_FAIL;
            return state;
        }
        tokenBuffer.push(ch);
        if (tokenBuffer.length() < 4) {
            state = TokenState.STATE_CONTINUE;
        } else {
            char next = TokenUtils.getNext(content, offset);
            charType = TokenUtils.getCharType(next);
            if (!CharType.CHAR_SPACE.equals(charType) && !CharType.CHAR_CHARACTER.equals(charType) && !CharType.CHAR_EOF.equals(charType)) {
                state = TokenState.STATE_FAIL;
            } else {
                String value = ObjectTypeUtils.convertType(tokenBuffer.value(TokenType.TOKEN_NULL), String.class);
                if ("null".equals(value) || "NULL".equals(value)) {
                    state = TokenState.STATE_END;
                } else {
                    state = TokenState.STATE_FAIL;
                }
            }
        }
        return state;
    }

    @Override
    public Token generateToken() {
        if (!TokenState.STATE_END.equals(state) && !TokenState.STATE_END_BACK.equals(state)) {
            return null;
        }
        return new Token(tokenBuffer.getStart(), tokenBuffer.getEnd(), TokenType.TOKEN_NULL, "null", null, tokenBuffer.buffer());
    }
}
